//
// Created by none98 on 2021/9/10.
//

#include "Acceptor.h"
#include "Selector.h"
#include <spdlog/spdlog.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include "EventLoop.h"
#include "arpa/inet.h"
#include "Channel.h"
#include "TcpConnection.h"
#include "InetAddress.h"

Acceptor::Acceptor(const std::string &address,int port, EventLoop* loop):
    channel(new Channel(0,Selector::READ)),
    port(port),
    loop(loop)
{
    this->fd = socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,0);
    if(fd<0) {
        spdlog::error("socket require error: {}",strerror(errno));
    }
    struct sockaddr_in addr;
    memset(&addr,0,sizeof(addr));
    addr.sin_port=htons(port);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr=inet_addr(address.data());
    bind(fd, reinterpret_cast<const sockaddr *>(&addr), sizeof(addr));
    //spdlog::info("server socket:{} at port {}",fd,this->port);
    if( listen(fd,1024)<0 ){
        spdlog::error("serversocket listen go wrong: {}",strerror(errno));
    }
    channel->SetFd(fd);
    channel->SetReadCallBack(std::bind(&Acceptor::HandleRead,this));
    channel->SetErrorCallBack(std::bind(&Acceptor::HandleError,this));
    loop->GetSelector()->RegisterChannel(channel.get());
}

Acceptor::~Acceptor() {
    close(fd);
    spdlog::info("server closed");
}


void Acceptor::HandleRead() {
    struct sockaddr_in addr;
    size_t len=sizeof(addr);
    memset(&addr,0,sizeof(addr));
    int newFd = accept4(fd, reinterpret_cast<sockaddr *>(&addr), reinterpret_cast<socklen_t *>(&len), SOCK_NONBLOCK);
    if(newFd<0){
        spdlog::error("accept go wrong: {}",strerror(errno));
    }else{
        TcpConnectionPtr conn = std::make_shared<TcpConnection>(newFd,nullptr);
        InetAddress localAddr(static_cast<int>(addr.sin_port), reinterpret_cast<char *>(&addr.sin_addr));
        conn->localAddress = localAddr;
        conn->closeInTcpServer=closeConnCallBack;
        //call Server::HandleNewConnction
        if(registerConnCallBack){
            registerConnCallBack(conn);
        }else{
            spdlog::error("connection register not found");
        }
        //User application connectionCallBack
        if(newConnectionCallBack)
            newConnectionCallBack(conn);
    }

}

void Acceptor::HandleError() {

}

